home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 2
/
Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso
/
Aminet
/
mus
/
play
/
tracker_3_19.lzh
/
tracker
/
amiga_support.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-17
|
15KB
|
762 lines
/* support functions for yours truly amiga */
/* $Id: amiga_support.c,v 1.2 1993/11/17 15:29:53 espie Exp espie $ */
/* $Log: amiga_support.c,v $
* Revision 1.2 1993/11/17 15:29:53 espie
* Added higher-level support. Separated plainly from audio.c
* */
#include <stdio.h>
#include "defs.h"
#include "extern.h"
#include "song.h"
#include "channel.h"
#include <hardware/cia.h>
#include <hardware/intbits.h>
#include <hardware/dmabits.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <devices/audio.h>
#include <devices/timer.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/timer.h>
#undef X
#include <proto/intuition.h>
#include <proto/gadtools.h>
LOCAL struct audio_channel
{
int amiga_number;
struct sample_info *samp;
int volume;
int pitch;
} chan[4];
LOCAL struct sample_info dummy =
{
NULL,
0,
0,
0,
0,
0,
0,
0,
NULL,
NULL
};
LOCAL int allocated = 0;
struct audio_channel *new_channel()
{
struct audio_channel *new;
new = &chan[allocated];
new->amiga_number = allocated++;
new->samp = &dummy;
new->volume = 0;
new->pitch = 0;
new->samp = 0;
return new;
}
void no_audio_channels()
{
allocated = 0;
}
/* list scanning.
* next is needed: with it, we can actually unlink the node while scanning
* the current list. Type is provided to avoid type-casting errors in
* SCANLIST expansion.
*/
#define SCANLIST(node, next, list, type) \
for((node) = (type)((struct MinList *)(list))->mlh_Head; \
(next) = (type)((struct MinNode *)(node))->mln_Succ; \
(node) = (next))
LOCAL char *version = "\0$VER: tracker 3.11";
/* remember allocated samples for cleaning up in panic case */
LOCAL struct MinList tracked_list;
/* timer variables:
* the message port
*/
LOCAL struct MsgPort *tport = 0;
/* the basic wait request */
LOCAL struct timerequest *tr = 0;
/* the reference system time at which the song started */
LOCAL struct EClockVal system_time;
LOCAL struct Library *TimerBase;
/* Clean up: Do we need to close timer ? */
LOCAL BOOL timer_opened = FALSE;
/* Not really useful */
LOCAL BOOL first_time = FALSE;
extern volatile struct CIA __far ciaa;
LOCAL void init_timer()
{
int fail;
tport = CreateMsgPort();
if (!tport)
{
exit(10);
}
tr = CreateIORequest(tport, sizeof(struct timerequest));
if (!tr)
{
exit(10);
}
fail = OpenDevice(TIMERNAME, UNIT_WAITECLOCK, tr, 0);
if (fail)
exit(10);
else
timer_opened = TRUE;
TimerBase = tr->tr_node.io_Device;
}
/* The basic user interface (a simple window) */
LOCAL struct IntuitionBase *IntuitionBase = 0;
LOCAL struct Library *GadtoolsBase = 0;
LOCAL struct Window *win;
/* We use topaz.font so as not to get into sizing problems */
LOCAL struct TextAttr topaz =
{
"topaz.font",
8,
0,
0
};
LOCAL struct NewGadget template =
{
10, 10, /* start position (offset from left/topedge)
72, 20, /* width/height */
NULL,
&topaz,
0, /* gadget ID */
0,
NULL,
NULL
};
LOCAL APTR vi;
LOCAL struct Screen *pub = 0;
LOCAL struct Gadget *glist;
/* we precisely have seven gadgets */
#define MAX_GADGET 7
/* all labelled with strings */
LOCAL char *label[MAX_GADGET] =
{
"Previous",
"Next",
"Restart",
"<<",
">>",
"NTSC",
"PAL",
};
/* and mapping to these commands of the normal tracker interface */
LOCAL char mapto[MAX_GADGET] = { 'p', 'n', 'r', '<', '>', 'S', 's' };
LOCAL void init_ui(void)
{
struct Gadget *gad;
int i;
IntuitionBase = OpenLibrary("intuition.library", 37);
if (!IntuitionBase)
exit(10);
GadtoolsBase = OpenLibrary("gadtools.library", 37);
if (!GadtoolsBase)
exit(10);
pub = LockPubScreen(NULL);
if (!pub)
exit(10);
vi = GetVisualInfo(pub, TAG_END);
if (!vi)
exit(10);
gad = CreateContext(&glist);
if (!gad)
exit(10);
template.ng_VisualInfo = vi;
/* set up Top/Left Edge of initial gadget according to Wbar */
template.ng_TopEdge += pub->WBorTop + pub->Font->ta_YSize + 1;
/* lay out gadgets */
for (i = 0; i < MAX_GADGET; i++)
{
template.ng_GadgetText = label[i];
gad = CreateGadget(BUTTON_KIND, gad, &template, TAG_END);
if (!gad)
exit(10);
template.ng_LeftEdge += template.ng_Width + 5;
template.ng_GadgetID++;
}
win = OpenWindowTags(NULL,
WA_Title, "Experiment IV",
WA_Width, template.ng_LeftEdge + 10,
WA_Height, template.ng_Height + template.ng_TopEdge + 10,
WA_MouseQueue, 35, /* we can't always answer messages */
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_DragBar, TRUE,
WA_SmartRefresh, TRUE, /* don't want to be bothered with refresh */
WA_Gadgets, glist,
WA_IDCMP, IDCMP_CLOSEWINDOW | BUTTONIDCMP | IDCMP_REFRESHWINDOW,
TAG_DONE, 0);
if (!win)
exit(10);
GT_RefreshWindow(win, NULL);
}
/* the audio interface */
/* we allow for lots more audio requests than we need */
#define QUEUE_LENGTH 50
LOCAL struct ext_audio
{
struct IOAudio request;
struct ext_audio *next;
}
/* the audio queue */
*first = 0,
/* the specific request that get used for closing/opening */
*req = 0;
LOCAL struct MsgPort *port = 0;
/* in order to clean up afterwards: */
LOCAL BOOL audio_opened = FALSE;
LOCAL void command_audio(struct ext_audio *io);
LOCAL void send_immediate(ULONG command, int mask);
LOCAL UBYTE whichchannel[] = {15};
/* allocate_channels(): sends a request to the audio.device for
* the channels.
*/
LOCAL void allocate_channels(void)
{
struct ext_audio *sweep;
req->request.ioa_Request.io_Command = ADCMD_ALLOCATE;
req->request.ioa_AllocKey = 0;
req->request.ioa_Data = whichchannel;
req->request.ioa_Length = sizeof(whichchannel);
command_audio(req);
for (sweep = first; sweep; sweep = sweep->next)
sweep->request.ioa_AllocKey = req->request.ioa_AllocKey;
}
/* free_channels(): give back the channels.
*/
LOCAL void free_channels(void)
{
req->request.ioa_Request.io_Command = ADCMD_FREE;
command_audio(req);
}
LOCAL struct ext_audio *create_request(void)
{
struct ext_audio *new;
new = AllocMem(sizeof(struct ext_audio), MEMF_CLEAR|MEMF_PUBLIC);
if (req)
*new = *req;
return new;
}
/* creates a whole queue of audio requests */
LOCAL void create_queue(void)
{
struct ext_audio *last, *new;
int i;
last = NULL;
for (i = 0; i < QUEUE_LENGTH; i++)
{
new = create_request();
new->next = last;
last = new;
}
first = new;
}
LOCAL void get_requests(void)
{
struct ext_audio *back;
while(back = GetMsg(port))
if (back != req) /* only those belonging to the queue */
{
back->next = first;
first = back;
}
}
LOCAL void send_immediate(ULONG command, int mask)
{
first->request.ioa_Request.io_Command = command;
first->request.ioa_Request.io_Flags = IOF_QUICK;
first->request.ioa_Request.io_Unit = mask;
BeginIO(first);
}
LOCAL void command_audio(struct ext_audio *io)
{
struct ext_audio *request;
BeginIO(io);
WaitPort(port);
get_requests();
}
LOCAL void reset_audio(void)
{
send_immediate(CMD_RESET, 15);
get_requests();
}
/* obtain_audio(): allocate all the structures we will need to
* play with the audio device
*/
LOCAL void obtain_audio(void)
{
BYTE fail;
port = CreateMsgPort();
if (!port)
{
fprintf(stderr, "Couldn't allocate port");
exit(10);
}
req = CreateIORequest(port, sizeof(struct ext_audio));
if (!req)
{
fprintf(stderr, "Couldn't allocate io request");
exit(10);
}
req->request.ioa_Request.io_Message.mn_Node.ln_Pri = 0;
/* Note that OpenDevice returns 0 on success
*/
fail = OpenDevice("audio.device", 0L, (struct IORequest *)req, 0L);
if (fail)
{
fprintf(stderr, "Couldn't open audio device");
exit(10);
}
else
audio_opened = TRUE;
}
/* remember old task priority at exit (CLI process runs on the CLI context,
* and reverts to being a shell with the same priority on exit
*/
LOCAL int oldpri;
LOCAL void amiga_init()
{
oldpri = SetTaskPri(FindTask(0), 15);
/* make cursor invisible, speed up output some */
printf("\233""0 p\n");
obtain_audio();
create_queue();
allocate_channels();
init_timer();
/* audio filter OFF */
ciaa.ciapra |= CIAF_LED;
init_ui();
}
LOCAL void amiga_cleanup()
{
struct MinNode *current, *next;
SetTaskPri(FindTask(0), oldpri);
printf("\233"" p\n");
if (win)
CloseWindow(win);
if (glist)
FreeGadgets(glist);
if (vi)
FreeVisualInfo(vi);
if (pub)
UnlockPubScreen(NULL, pub);
if (IntuitionBase)
CloseLibrary(IntuitionBase);
if (GadtoolsBase)
CloseLibrary(GadtoolsBase);
SCANLIST(current, next, &tracked_list, struct MinNode *)
FreeVec(current);
if (req->request.ioa_AllocKey)
free_channels();
if (audio_opened)
CloseDevice(req);
if (req)
DeleteIORequest(req);
if (port)
DeletePort(port);
while(first)
{
struct ext_audio *temp;
temp = first;
first = first->next;
FreeMem(temp, sizeof(struct ext_audio));
}
if (timer_opened)
{
if (!CheckIO(tr))
{
AbortIO(tr);
WaitIO(tr);
}
CloseDevice(tr);
}
if (tr)
DeleteIORequest(tr);
if (tport)
DeleteMsgPort(tport);
ciaa.ciapra &= ~CIAF_LED;
}
/* indispensible for not losing memory ! */
void __regargs __chkabort()
{
}
void *alloc_sample(int len)
{
char *s;
s = AllocVec(len + sizeof(struct MinNode), MEMF_CHIP | MEMF_CLEAR);
if (!s)
return 0;
AddTail(&tracked_list, s);
return s + sizeof(struct MinNode);
}
void free_sample(char *s)
{
s -= sizeof(struct MinNode);
Remove(s);
FreeVec(s);
}
/* termio */
BOOL run_in_fg()
{
return 1;
}
void nonblocking_io()
{
static BOOL yet = 0;
if (!yet)
{
NewList(&tracked_list);
atexit(amiga_cleanup);
amiga_init();
yet = 1;
}
}
void sane_tty()
{
}
int may_getchar()
{
struct IntuiMessage *msg;
int id;
if (SetSignal(0,0) & SIGBREAKF_CTRL_C)
exit(10);
while(msg = GT_GetIMsg(win->UserPort))
switch(msg->Class)
{
case IDCMP_CLOSEWINDOW:
GT_ReplyIMsg(msg);
return 'q';
case IDCMP_REFRESHWINDOW:
GT_ReplyIMsg(msg);
GT_BeginRefresh(win);
GT_EndRefresh(win, TRUE);
break;
case IDCMP_GADGETUP:
id = ((struct Gadget *)msg->IAddress)->GadgetID;
GT_ReplyIMsg(msg);
return mapto[id];
default:
GT_ReplyIMsg(msg);
}
return -1;
}
/* audio */
/* empty operation on the amiga */
void init_tables(oversample, frequency, chan)
int oversample, frequency;
struct channel *chan;
{
}
void resample(chan, oversample, number)
struct channel *chan;
int oversample;
int number;
{
int i;
/*
if (first_time)
{
first_time = FALSE;
system_time.tv_micro += number;
}
*/
tr->tr_node.io_Command = TR_ADDREQUEST;
tr->tr_time.tv_secs = system_time.ev_hi;
tr->tr_time.tv_micro = system_time.ev_lo;
SendIO(tr);
WaitPort(tport);
while(GetMsg(tport))
;
system_time.ev_lo += (unsigned long)number;
if (system_time.ev_lo < (unsigned long)number)
system_time.ev_hi++;
}
void play_note(au, samp, pitch)
struct audio_channel *au;
struct sample_info *samp;
int pitch;
{
au->pitch = pitch;
send_immediate(CMD_FLUSH, 1 << au->amiga_number);
get_requests();
if (samp)
{
au->samp = samp;
if (au->samp->start)
{
first->request.ioa_Request.io_Command = CMD_WRITE;
first->request.ioa_Request.io_Flags = ADIOF_PERVOL;
first->request.ioa_Request.io_Unit = 1<<au->amiga_number;
first->request.ioa_Data = au->samp->start;
first->request.ioa_Length = au->samp->length;
first->request.ioa_Period = au->pitch;
first->request.ioa_Volume = au->volume;
first->request.ioa_Cycles = 1;
BeginIO(first);
first = first->next;
if (au->samp->rp_start)
{
first->request.ioa_Request.io_Command = CMD_WRITE;
first->request.ioa_Request.io_Flags = 0;
first->request.ioa_Request.io_Unit = 1<<au->amiga_number;
first->request.ioa_Data = au->samp->rp_start;
first->request.ioa_Length = au->samp->rp_length;
first->request.ioa_Cycles = 0;
BeginIO(first);
first = first->next;
}
}
}
}
void set_play_pitch(au, pitch)
struct audio_channel *au;
int pitch;
{
if (pitch != au->pitch)
{
au->pitch = pitch;
first->request.ioa_Period = pitch;
first->request.ioa_Volume = au->volume;
send_immediate(ADCMD_PERVOL, 1 << au->amiga_number);
}
}
void set_play_volume(au, volume)
struct audio_channel *au;
int volume;
{
if (volume != au->volume)
{
au->volume = volume;
first->request.ioa_Period = au->pitch;
first->request.ioa_Volume = volume;
send_immediate(ADCMD_PERVOL, 1 << au->amiga_number);
}
}
void set_position(au, pos)
struct audio_channel *au;
int pos;
{
send_immediate(CMD_FLUSH, 1 << au->amiga_number);
get_requests();
if (au->samp->start)
{
if (pos < au->samp->length)
{
first->request.ioa_Request.io_Command = CMD_WRITE;
first->request.ioa_Request.io_Flags = ADIOF_PERVOL;
first->request.ioa_Request.io_Unit = 1<<au->amiga_number;
first->request.ioa_Data = au->samp->start + pos;
first->request.ioa_Length = au->samp->length - pos;
first->request.ioa_Period = au->pitch;
first->request.ioa_Volume = au->volume;
first->request.ioa_Cycles = 1;
BeginIO(first);
first = first->next;
if (au->samp->rp_start)
{
first->request.ioa_Request.io_Command = CMD_WRITE;
first->request.ioa_Request.io_Flags = 0;
first->request.ioa_Request.io_Unit = 1<<au->amiga_number;
first->request.ioa_Data = au->samp->rp_start;
first->request.ioa_Length = au->samp->rp_length;
first->request.ioa_Cycles = 0;
BeginIO(first);
first = first->next;
}
}
}
}
void set_mix(percent)
int percent;
{
}
int open_audio(f, s)
int f, s;
{
first_time = TRUE;
return ReadEClock(&system_time); /* samples/sec used as a timing unit: 1sec =1 000 000 µs */
}
void set_synchro(s)
BOOL s;
{
ReadEClock(&system_time);
first_time = TRUE;
}
int update_frequency()
{
return 0;
}
void output_samples(int left, int right)
{
}
void flush_buffer(void)
{
}
void discard_buffer(void)
{
reset_audio();
}
void close_audio(void)
{
}
/* amiga: popen() for OS2_04 */
#include <proto/dos.h>
#include <dos/dostags.h>
#include <stdio.h>
#include <string.h>
/*
### CSupport/popen
###
### NAME
### popen/pclose -- Unix-like pipes
###
### STATUS
### Experimental
###
*/
FILE *popen(char *command, char *mode)
{
if (strcmp(mode, "r") == 0)
/* open pipe for reading */
{
FILE *reader;
BPTR writer, null;
writer = Open("PIPE:", MODE_NEWFILE);
reader = fopen("PIPE:", "r");
null = Open("NIL:", MODE_NEWFILE);
if (SystemTags(command, SYS_Input, null,
SYS_Output, writer, SYS_Asynch, TRUE, TAG_END) == -1)
{
Close(null);
Close(writer);
fclose(reader);
return NULL;
}
else
return reader;
}
else if (strcmp(mode, "w") == 0)
/* open pipe for writing */
{
FILE *writer;
BPTR reader, null;
writer = fopen("PIPE:", "w");
reader = Open("PIPE:", MODE_OLDFILE);
null = Open("NIL:", MODE_NEWFILE);
if (SystemTags(command, SYS_Input, reader,
SYS_Output, null, SYS_Asynch, TRUE, TAG_END) == -1)
{
Close(null);
Close(reader);
fclose(writer);
return NULL;
}
else
return writer;
}
else
return NULL;
}
/* for us, pclose is just fclose.
* We hope everything will close out alright
*/
void pclose(FILE *f)
{
fclose(f);
}